﻿// Imports
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.UI;

namespace Nickel
{

    /// <summary>
    /// Handles write actions
    /// </summary>
    public class Write : Page
    {

        /// <summary>
        /// Handles page load
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Event arguments</param>
        protected void Page_Load(object sender, EventArgs e)
        {

            // Get user
            Author user = Account.GetSignedInAuthor(Data, Request.Cookies[Settings.COOKIE_NAME]);

            // Must be logged in to do anything at this page
            if (user == null)
            {

                // Write error
                Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Request.Form[Constants.TYPE_COMMENT] == null ? Errors.NOT_SIGNED_IN : Errors.NOT_SIGNED_IN_COMMENTS) + "\" }");

            }
            else
            {

                #region Article

                // Articles
                if (Request.Form[Constants.TYPE_ARTICLE] != null)
                {

                    // Must be admin
                    if (!user.Admin)
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ADMIN_REQUIRED) + "\" }");

                    }
                    else
                    {

                        // Declare article
                        Article article = null;

                        // ID sent
                        if (Request.Form[Constants.INPUT_ID] != null)
                        {

                            // Get article
                            article = Data.GetArticleById(Request.Form[Constants.INPUT_ID]);

                            // No article found using this ID
                            if (article == null)
                            {

                                // Write error
                                Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ARTICLE_ID_INVALID) + "\" }");

                            }
                            else
                            {

                                // Deleting article
                                if (Request.Form[Constants.INPUT_DELETE] == "true")
                                {

                                    // Deleting article for real
                                    if (Request.Form[Constants.INPUT_SUBMIT] != null)
                                    {

                                        // Remove article
                                        Data.Articles.Remove(article);

                                        // Save
                                        Data.Save();

                                        // Build response
                                        string strResponse = "<h1>" + Titles.ARTICLE_DELETE + "</h1>";
                                        strResponse += "<p>" + Responses.ARTICLE_DELETED + "</p>";

                                        // Write response
                                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResponse) + "\" }");

                                    }
                                    else
                                    {

                                        // Build article delete form string
                                        string strForm = "<div id=\"" + Constants.SOURCE_FORM + "\">" +
                                            "<h1>" + Titles.ARTICLE_DELETE + "</h1>" +
                                            "<div class=\"formLine\">" +
                                            Instructions.ARTICLE_DELETE +
                                            "&nbsp;<input type=\"button\" name=\"" + 
                                            Constants.INPUT_SUBMIT + "\" id=\"" + 
                                            Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + 
                                            Constants.SOURCE_FORM + "', '" +
                                            Constants.TYPE_ARTICLE + "', '" + 
                                            article.ID + 
                                            "', true);\" value=\"" + 
                                            Labels.SUBMIT_DELETE + "\" />" +
                                            "<div id=\"" + Constants.TARGET_FORM_ERROR + "\" class=\"deleteArticleError\"></div>" + 
                                            "</div>" + 
                                            "</div>";

                                        // Write response
                                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                                    }

                                }
                                else
                                {

                                    // Updating article
                                    if (Request.Form[Constants.INPUT_SUBMIT] != null)
                                    {

                                        // Update article
                                        article.Published = Request.Form[Constants.INPUT_PUBLISH] == "true";

                                        // Add new tags, if any
                                        AddNewTags();

                                        // Update article with form data
                                        strError = article.Update(Request.Form);
                                        if (strError.Length > 0)
                                        {

                                            // Write error
                                            Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(strError) + "\" }");

                                        }
                                        else
                                        {

                                            // Check duplicate
                                            string strDupeType = Data.TitleExists(article.Title, article.ID, Server.MapPath(@"~/"));
                                            if (strDupeType == string.Empty)
                                            {

                                                // Update article with form data
                                                article.Update(Request.Form);

                                                // Re-sort
                                                Data.Articles.Sort(Sort.ArticleByDate);

                                                // Save
                                                Data.Save();

                                                // Build result string
                                                string strResult = "<div id=\"" + Constants.RESPONSE_ID + "\"><h1>" + Titles.ARTICLE_UPDATE + "</h1>" +
                                                    "<p>Your article has been updated! Click <a href=\"" + strBaseUrl + StringHelper.Encode(article.Title) +
                                                    "\">here</a> to check it out.</p></div>";

                                                // Write form
                                                Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                                            }
                                            else
                                            {

                                                // Write error
                                                Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.TITLE_EXISTS) + "\" }");

                                            }

                                        }

                                    }
                                    else
                                    {

                                        // Write form
                                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(article.Form(Data.Tags, strBaseUrl + Constants.ACTION_UPLOAD)) + "\" }");

                                    }

                                }

                            }

                        }
                        else
                        {

                            // Create new article
                            article = new Article();
                            article.Author = user.ID;

                            // Submitting new article
                            if (Request.Form[Constants.INPUT_SUBMIT] != null)
                            {

                                // Update article with form data
                                strError = article.Update(Request.Form);
                                if (strError.Length > 0)
                                {

                                    // Write error
                                    Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(strError) + "\" }");

                                } 
                                else 
                                {

                                    // Add new tags, if any
                                    AddNewTags();

                                    // Check duplicate
                                    string strDupeType = Data.TitleExists(article.Title, Server.MapPath(@"~/"));
                                    if (strDupeType == string.Empty)
                                    {

                                        // Add and sort articles
                                        Data.Articles.Add(article);
                                        Data.Articles.Sort(Sort.ArticleByDate);

                                        // Save data
                                        Data.Save();

                                        // Build result string
                                        string strResult = "<div id=\"" + Constants.RESPONSE_ID + "\"><h1>" + Titles.ARTICLE_NEW + "</h1>" +
                                            "<p>Your new article has been added! Click <a href=\"" + strBaseUrl + StringHelper.Encode(article.Title) +
                                            "\">here</a> to check it out.</p></div>";

                                        // Write form
                                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                                    }
                                    else
                                    {

                                        // Write error
                                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.TITLE_EXISTS) + "\" }");

                                    }

                                }

                            }
                            else
                            {

                                // Write form
                                Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(article.Form(Data.Tags, strBaseUrl + Constants.ACTION_UPLOAD)) + "\" }");

                            }

                        }

                        // Clean up
                        article = null;

                    }

                }
                
                #endregion
                #region Comment

                // Articles
                if (Request.Form[Constants.TYPE_COMMENT] != null)
                {

                    // Parent article required
                    if (Request.Form[Constants.INPUT_ARTICLE_ID] == null )
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ARTICLE_ID_INVALID) + "\" }");

                    } 
                    else 
                    {

                        // Declare parent article
                        Article article = Data.GetArticleById(Request.Form[Constants.INPUT_ARTICLE_ID]);

                        // No article found using this ID
                        if (article == null)
                        {

                            // Write error
                            Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ARTICLE_ID_INVALID) + "\" }");

                        }
                        else
                        {

                            // Declare comment
                            Comment comment = null;

                            // ID specified
                            if (Request.Form[Constants.INPUT_ID] != null)
                            {

                                // Get comment
                                comment = article.GetCommentById(Request.Form[Constants.INPUT_ID]);

                                // Comment not found
                                if (comment == null)
                                {

                                    // Write error
                                    Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.COMMENT_ID_INVALID) + "\" }");

                                }
                                else
                                {

                                    // User must be admin or comment author to edit
                                    if (user.Admin || comment.Author == user.ID)
                                    {

                                        // Submitting form
                                        if (Request.Form[Constants.INPUT_SUBMIT] != null)
                                        {

                                            // Deleting
                                            if (Request.Form[Constants.INPUT_DELETE] != null)
                                            {

                                                // Delete comment
                                                article.Comments.Remove(comment);

                                                // Save
                                                Data.Save();

                                                // Send back delete string to clear comment
                                                Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"delete\" }");

                                            }
                                            else
                                            {

                                                // Update comment
                                                comment.ModifiedDateTime = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);
                                                comment.Text = Request.Form[Constants.INPUT_TEXT];

                                                // Save
                                                Data.Save();

                                                // Write message
                                                Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(comment.Html(Data, user, GetCommentProfileImage(comment))) + "\" }");

                                            }

                                        }
                                        else
                                        {

                                            // Deleting
                                            if (Request.Form[Constants.INPUT_DELETE] != null)
                                            {

                                                // Start form
                                                string strForm = "<div id=\"" + Constants.SOURCE_FORM + "\">" +
                                                    "<h4 class=\"updateComment\">" + Titles.COMMENT_DELETE + "</h4>" +
                                                    "<div class=\"formLine\" style=\"margin-top:10px;\">" + Instructions.COMMENT_DELETE +
                                                    "&nbsp;<input type=\"button\" name=\"" +
                                                    Constants.INPUT_SUBMIT + "\" id=\"" +
                                                    Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" +
                                                    Constants.SOURCE_FORM + "', '" +
                                                    Constants.TYPE_COMMENT + "', '" +
                                                    comment.ID +
                                                    "', true);\" value=\"" +
                                                    Labels.SUBMIT_DELETE + "\" /></div></div>" +
                                                    "<p id=\"" + comment.ID + "formError\" name=\"" + comment.ID + "formError\" class=\"formError\"></p>";

                                                // Write delete form 
                                                Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                                            }
                                            else
                                            {

                                                // Write edit form
                                                Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(comment.Form) + "\" }");

                                            }

                                        }

                                    }
                                    else
                                    {

                                        // Write error
                                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.UNAUTHORIZED) + "\" }");

                                    }

                                }

                            }
                            else
                            {

                                // Create empty comment
                                comment = new Comment();

                                // Submitting form
                                if (Request.Form[Constants.INPUT_SUBMIT] != null)
                                {

                                    // Create comment
                                    comment.Author = user.ID;
                                    comment.CreationDateTime = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);
                                    comment.ID = StringHelper.NewGuid;
                                    comment.ModifiedDateTime = comment.CreationDateTime;
                                    comment.Text = Request.Form[Constants.INPUT_TEXT];

                                    // Add comment to article
                                    article.Comments.Add(comment);
                                    article.Comments.Sort(Sort.CommentByDate);
                                        
                                    // Save
                                    Data.Save();

                                    // Article is published
                                    if (article.Published)
                                    {

                                        // Iterate through subscribers
                                        foreach (string subscriberID in article.Subscriptions)
                                        {

                                            // Get author
                                            Author subscriber = Data.GetAuthorById(subscriberID);
                                            if (subscriber != null)
                                            {

                                                // Don't notify poster
                                                if (subscriber.ID != user.ID)
                                                {

                                                    // Set subject
                                                    string strSubject = Settings.SITE_NAME + " subscription notification :: " + article.Title + " has been updated";

                                                    // Set body
                                                    string strBody = "This is a friendly note to alert you that comments " +
                                                        "have been added to the article titled \"" + article.Title + "\". " +
                                                        "To view this article and its comments, or to change your subscription, " +
                                                        "please visit " + strBaseUrl + StringHelper.Encode(article.Title) + ".\n\n" +
                                                        "Thanks,\n" +
                                                        Settings.SITE_OWNER;

                                                    // Send message
                                                    Mail.Send(subscriber.Email, strSubject, strBody);

                                                }

                                            }

                                        }

                                    }

                                    // Send back new comment
                                    Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(comment.Html(Data, user, GetCommentProfileImage(comment))) + "\" }");

                                }
                                else
                                {

                                    // Write form
                                    Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(comment.Form) + "\" }");

                                }

                            }

                        }

                    }

                }

                #endregion
                #region Tags

                // Editing tags
                if (Request.Form[Constants.TYPE_TAGS] != null)
                {

                    // Must be admin
                    if (!user.Admin)
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ADMIN_REQUIRED) + "\" }");

                    }
                    else
                    {

                        // No values sent
                        if (Request.Form[Constants.INPUT_TAG_LIST] == null)
                        {

                            // Build tag form string
                            string strForm = "<div id=\"" + Constants.SOURCE_FORM + "\">" +
                                "<h1>" + Titles.TAGS + "</h1>" +
                                "<p>" + Instructions.TAGS + "</p>" +
                                "<textarea name=\"" + Constants.INPUT_TAG_LIST + "\" id=\"" + Constants.INPUT_TAG_LIST + "\">" + Data.Tags.Join(", ") + "</textarea>" +
                                "<div class=\"formLine\">" +
                                "<div class=\"tagListSubmit\"><input type=\"button\" name=\"" + Constants.INPUT_SUBMIT + "\" id=\"" + Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_TAGS + "');\" value=\"" + Labels.SUBMIT_TAGS + "\" /></div>" +
                                "<div id=\"" + Constants.TARGET_FORM_ERROR + "\"></div>" + 
                                "</div></div>";

                            // Write form
                            Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                        }
                        else
                        {

                            // Clear tags
                            Data.Tags.Clear();

                            // Build new tag list
                            foreach (string tag in Request.Form[Constants.INPUT_TAG_LIST].Split(",".ToCharArray())) 
                                if (tag.ToLower().Trim().Length > 0) 
                                    Data.Tags.Add(tag.ToLower().Trim());


                            // Sort
                            Data.Tags.Sort();

                            // Iterate through articles
                            foreach (Article article in Data.Articles)
                            {

                                // Create list to hold tags to remove
                                List<string> removeTags = new List<string>();

                                // Iterate through article tags
                                foreach (string articleTag in article.Tags)
                                {

                                    // Set found flag
                                    bool bFound = false;

                                    // Find tag
                                    foreach (string tag in Data.Tags) 
                                        if (tag == articleTag.ToLower().Trim()) 
                                            bFound = true;

                                    // Add to list if tag not found
                                    if (!bFound) 
                                        removeTags.Add(articleTag);

                                }

                                // Remove tag
                                foreach (string removeTag in removeTags) 
                                    article.Tags.Remove(removeTag);

                            }

                            // Save data
                            Data.Save();

                            // Build confirmation message
                            string strResult = "<div id=\"" + Constants.RESPONSE_ID + "\"><h1>" + Titles.TAGS + "</h1>" +
                                "<p>Tags updated successfully, yo! refresh the page or click <a href=\"" + strBaseUrl + "\">here</a> to return to the home page to see your changes.</p></div>";

                            // Write form
                            Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                        }

                    }

                }

                #endregion

            }

            // Clean up
            user = null;

        }

        /// <summary>
        /// Add new tags
        /// </summary>
        private void AddNewTags()
        {

            // Iterate through new tags
            foreach (string newTag in Request.Form[Constants.INPUT_TAG_LIST].Split(",".ToCharArray()))
            {

                // Clean up tag
                string strNewTag = newTag.ToLower().Trim();

                // Check new tag length
                if (strNewTag.Length > 0)
                {

                    // Check if new tag already exists
                    bool bTagExists = false;
                    foreach (string tag in Data.Tags) 
                        if (tag.ToLower() == strNewTag) 
                            bTagExists = true;

                    // Add new tag if not found
                    if (!bTagExists) 
                        Data.Tags.Add(strNewTag);

                }

            }

            // Sort tags
            Data.Tags.Sort();

        }

    }

}
